package mhttp

import (
	"bytes"
	"encoding/json"
	"gitee.com/dennis-mxx/gcode-common/mcontext"
	"io"
	"mime/multipart"
	"net/http"
	"strings"
)

type Request struct {
	Mtx     *mcontext.MContext
	Url     string
	Method  string
	Params  map[string]string
	Head    http.Header
	Body    io.Reader
	Charset string
	Handler HttpHandler
}

func (ce *Request) AddHeader(headerName, headerValue string) *Request {
	ce.Head.Set(headerName, headerValue)
	return ce
}

func (ce *Request) AddHeaderMap(header map[string]string) *Request {
	for k, v := range header {
		ce.Head.Set(k, v)
	}
	return ce
}

func (ce *Request) Get() (*Response, error) {
	ce.Head.Set("Content-Type", "application/x-www-form-urlencoded;charset="+ce.Charset)
	return ce.Handler.Run(ce, nil)
}
func (ce *Request) GetParams(params map[string]string) (*Response, error) {
	ce.Head.Set("Content-Type", "application/x-www-form-urlencoded;charset="+ce.Charset)
	ce.Params = params
	return ce.Handler.Run(ce, nil)
}

func (ce *Request) JsonBody(data string) (*Response, error) {
	return ce.JsonBody3(bytes.NewBufferString(data))
}
func (ce *Request) JsonBody2(data any) (*Response, error) {
	if b, err := json.Marshal(data); err == nil {
		return ce.JsonBody3(bytes.NewReader(b))
	} else {
		return nil, err
	}
}
func (ce *Request) JsonBody3(reader io.Reader) (*Response, error) {
	ce.Head.Set("Content-Type", "application/json;charset="+ce.Charset)
	return ce.Handler.Run(ce, reader)
}

func (ce *Request) FormBody(data string) (*Response, error) {
	return ce.FormBody3(bytes.NewBufferString(data))
}
func (ce *Request) FormBody2(data map[string]string) (*Response, error) {
	builder := &strings.Builder{}
	for k, v := range data {
		if v != "" {
			builder.WriteString(k + "=" + v + "&")
		}
	}
	if builder.Len() > 0 {
		return ce.FormBody(builder.String()[:builder.Len()-1])
	}
	return ce.FormBody("")
}

func (ce *Request) FormBody3(reader io.Reader) (*Response, error) {
	ce.Head.Set("Content-Type", "application/x-www-form-urlencoded;charset="+ce.Charset)
	return ce.Handler.Run(ce, reader)
}

func (ce *Request) File(fieldName, filename string, reader io.Reader) (*Response, error) {
	return ce.File2(fieldName, filename, reader, nil)
}
func (ce *Request) File2(fieldName, filename string, reader io.Reader, attr map[string]string) (*Response, error) {
	var buffer bytes.Buffer
	w := multipart.NewWriter(&buffer)
	for k, v := range attr {
		if err := w.WriteField(k, v); err != nil {
			return nil, err
		}
	}

	if formFile, err := w.CreateFormFile(fieldName, filename); err == nil {
		if _, err = io.Copy(formFile, reader); err != nil {
			ce.Head.Set("Content-Type", w.FormDataContentType())
			return ce.Handler.Run(ce, &buffer)
		} else {
			return nil, err
		}
	} else {
		return nil, err
	}
}
